package com.szl.group.utils;

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;


/**
 * description: 日期工具类
 * author: shenxiaolong
 * date: 2020/7/2  16:57
 */
@SuppressWarnings("all")
public class DateUtils {

    public final static String FORMAT_YYYYMMDD_HHMMSS = "yyyy-MM-dd HH:mm:ss";
    final static int[] SEASON = {1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4};


    /**
     * 获取当天的开始时间
     *
     * @return yyyy-MM-dd HH:mm:ss  格式
     */
    public static Date getDayBegin() {

        Date date = new Date();
        return getDayStartTime(date);
    }

    /**
     * 获取当天的结束时间
     *
     * @return yyyy-MM-dd HH:mm:ss  格式
     */
    public static Date getDayEnd() {

        Date date = new Date();
        return getDayEndTime(date);
    }

    /**
     * 获取昨天的开始时间
     *
     * @return 默认格式 Wed May 31 14:47:18 CST 2017
     */
    public static Date getBeginDayOfYesterday() {

        Calendar cal = new GregorianCalendar();
        cal.setTime(getDayBegin());
        cal.add(Calendar.DAY_OF_MONTH, -1);

        return cal.getTime();
    }

    /**
     * 获取昨天的结束时间
     *
     * @return 默认格式 Wed May 31 14:47:18 CST 2017
     */
    public static Date getEndDayOfYesterday() {

        Calendar cal = new GregorianCalendar();
        cal.setTime(getDayEnd());
        cal.add(Calendar.DAY_OF_MONTH, -1);

        return cal.getTime();
    }

    /**
     * 获取明天的开始时间
     *
     * @return 默认格式 Wed May 31 14:47:18 CST 2017
     */
    public static Date getBeginDayOfTomorrow() {

        Calendar cal = new GregorianCalendar();
        cal.setTime(getDayBegin());
        cal.add(Calendar.DAY_OF_MONTH, 1);

        return cal.getTime();
    }

    /**
     * 获取明天的结束时间
     *
     * @return 默认格式 Wed May 31 14:47:18 CST 2017
     */
    public static Date getEndDayOfTomorrow() {

        Calendar cal = new GregorianCalendar();
        cal.setTime(getDayEnd());
        cal.add(Calendar.DAY_OF_MONTH, 1);

        return cal.getTime();
    }

    /**
     * 获取本周的开始时间
     *
     * @return yyyy-MM-dd HH:mm:ss  格式
     */
    public static Date getBeginDayOfWeek() {

        Date date = new Date();
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);

        int dayofweek = cal.get(Calendar.DAY_OF_WEEK);
        if (dayofweek == 1) {
            dayofweek += 7;
        }
        cal.add(Calendar.DATE, 2 - dayofweek);

        return getDayStartTime(cal.getTime());
    }

    /**
     * 获取本周的结束时间
     *
     * @return yyyy-MM-dd HH:mm:ss  格式
     */
    public static Date getEndDayOfWeek() {

        Calendar cal = Calendar.getInstance();
        cal.setTime(getBeginDayOfWeek());
        cal.add(Calendar.DAY_OF_WEEK, 6);
        Date weekEndSta = cal.getTime();

        return getDayEndTime(weekEndSta);
    }

    /**
     * 获取本月的开始时间
     *
     * @return yyyy-MM-dd HH:mm:ss  格式
     */
    public static Date getBeginDayOfMonth() {

        Calendar calendar = Calendar.getInstance();
        calendar.set(getNowYear(), getNowMonth() - 1, 1);

        return getDayStartTime(calendar.getTime());
    }

    /**
     * 获取本月的结束时间
     *
     * @return yyyy-MM-dd HH:mm:ss  格式
     */
    public static Date getEndDayOfMonth() {

        Calendar calendar = Calendar.getInstance();
        calendar.set(getNowYear(), getNowMonth() - 1, 1);
        int day = calendar.getActualMaximum(5);
        calendar.set(getNowYear(), getNowMonth() - 1, day);

        return getDayEndTime(calendar.getTime());
    }

    /**
     * 获取上月的开始时间
     *
     * @return yyyy-MM-dd HH:mm:ss  格式
     */
    public static Date getBeginDayOfLastMonth() {

        Calendar calendar = Calendar.getInstance();
        calendar.set(getNowYear(), getNowMonth() - 2, 1);

        return getDayStartTime(calendar.getTime());
    }

    /**
     * 获取上月的结束时间
     *
     * @return yyyy-MM-dd HH:mm:ss  格式
     */
    public static Date getEndDayOfLastMonth() {

        Calendar calendar = Calendar.getInstance();
        calendar.set(getNowYear(), getNowMonth() - 2, 1);
        int day = calendar.getActualMaximum(5);
        calendar.set(getNowYear(), getNowMonth() - 2, day);

        return getDayEndTime(calendar.getTime());
    }

    /**
     * 获取某月的开始时间
     *
     * @return yyyy-MM-dd  格式
     */
    public static String formatBeginDay(int start) {

        Calendar calendar = Calendar.getInstance();
        calendar.set(getNowYear(), getNowMonth() - start, 1);
        Timestamp dayStartTime = getDayStartTime(calendar.getTime());

        return formatDateMonthString(dayStartTime);
    }

    /**
     * 获取某月的开始时间
     *
     * @return yyyy-MM  格式
     */
    public static String formatBeginDayOfMonth(int start) {

        Calendar calendar = Calendar.getInstance();
        calendar.set(getNowYear(), getNowMonth() - start, 1);
        Timestamp dayStartTime = getDayStartTime(calendar.getTime());

        return formatDateMonthString(dayStartTime);
    }

    /**
     * 获取某月的结束时间
     *
     * @return yyyy-MM-dd  格式
     */
    public static String formatEndDayOfMonth(int end) {

        Calendar calendar = Calendar.getInstance();
        calendar.set(getNowYear(), getNowMonth() - end, 1);
        int day = calendar.getActualMaximum(5);
        calendar.set(getNowYear(), getNowMonth() - end, day);
        Timestamp dayEndTime = getDayEndTime(calendar.getTime());

        return formatTimestamp2DateStringPoint(dayEndTime);
    }

    /**
     * 获取本年的开始时间
     *
     * @return yyyy-MM-dd HH:mm:ss  格式
     */
    public static Date getBeginDayOfYear() {

        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, getNowYear());
        cal.set(Calendar.MONTH, Calendar.JANUARY);
        cal.set(Calendar.DATE, 1);

        return getDayStartTime(cal.getTime());
    }

    /**
     * 获取本年的结束时间
     *
     * @return yyyy-MM-dd HH:mm:ss  格式
     */
    public static Date getEndDayOfYear() {

        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, getNowYear());
        cal.set(Calendar.MONTH, Calendar.DECEMBER);
        cal.set(Calendar.DATE, 31);

        return getDayEndTime(cal.getTime());
    }

    /**
     * 获取某个日期的开始时间
     *
     * @param d
     * @return yyyy-MM-dd HH:mm:ss  格式
     */
    public static Timestamp getDayStartTime(Date d) {

        Calendar calendar = Calendar.getInstance();
        if (null != d) calendar.setTime(d);
        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
        calendar.set(Calendar.MILLISECOND, 0);

        return new Timestamp(calendar.getTimeInMillis());
    }

    /**
     * 获取某个日期的结束时间
     *
     * @param d
     * @return yyyy-MM-dd HH:mm:ss  格式
     */
    public static Timestamp getDayEndTime(Date d) {

        Calendar calendar = Calendar.getInstance();
        if (null != d) calendar.setTime(d);
        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 23, 59, 59);
        calendar.set(Calendar.MILLISECOND, 999);

        return new Timestamp(calendar.getTimeInMillis());
    }

    /**
     * 获取某年某月的第一天
     *
     * @param year
     * @param month
     * @return
     */
    public static Date getStartMonthDate(int year, int month) {

        Calendar calendar = Calendar.getInstance();
        calendar.set(year, month - 1, 1);

        return calendar.getTime();
    }

    /**
     * 获取某年某月的最后一天
     *
     * @param year
     * @param month
     * @return
     */
    public static Date getEndMonthDate(int year, int month) {

        Calendar calendar = Calendar.getInstance();
        calendar.set(year, month - 1, 1);
        int day = calendar.getActualMaximum(5);
        calendar.set(year, month - 1, day);

        return calendar.getTime();
    }

    /**
     * 获取今年是哪一年
     *
     * @return
     */
    public static Integer getNowYear() {

        Date date = new Date();
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);

        return Integer.valueOf(gc.get(1));
    }

    /**
     * 获取本月是哪一月
     *
     * @return
     */
    public static int getNowMonth() {

        Date date = new Date();
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);

        return gc.get(2) + 1;
    }

    /**
     * 两个日期相减得到的天数
     *
     * @param beginDate
     * @param endDate
     * @return
     */
    public static int getDiffDays(Date beginDate, Date endDate) {

        if (beginDate == null || endDate == null) {
            throw new IllegalArgumentException("getDiffDays param is null!");
        }

        long diff = (endDate.getTime() - beginDate.getTime())
                / (1000 * 60 * 60 * 24);

        int days = new Long(diff).intValue();

        return days;
    }

    /**
     * 两个日期相减得到的毫秒数
     *
     * @param beginDate
     * @param endDate
     * @return
     */
    public static long dateDiff(Date beginDate, Date endDate) {

        long date1ms = beginDate.getTime();
        long date2ms = endDate.getTime();

        return date2ms - date1ms;
    }

    /**
     * 获取两个日期中的最大日期
     *
     * @param beginDate
     * @param endDate
     * @return
     */
    public static Date max(Date beginDate, Date endDate) {
        if (beginDate == null) {
            return endDate;
        }
        if (endDate == null) {
            return beginDate;
        }
        if (beginDate.after(endDate)) {
            return beginDate;
        }
        return endDate;
    }

    /**
     * 获取两个日期中的最小日期
     *
     * @param beginDate
     * @param endDate
     * @return
     */
    public static Date min(Date beginDate, Date endDate) {

        if (beginDate == null) {
            return endDate;
        }
        if (endDate == null) {
            return beginDate;
        }
        if (beginDate.after(endDate)) {
            return endDate;
        }
        return beginDate;
    }

    /**
     * 返回某月该季度的第一个月
     *
     * @param date
     * @return
     */
    public static Date getFirstSeasonDate(Date date) {

        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int sean = SEASON[cal.get(Calendar.MONTH)];
        cal.set(Calendar.MONTH, sean * 3 - 3);
        return cal.getTime();
    }

    /**
     * 返回某个日期下几天的日期
     *
     * @param date
     * @param i
     * @return
     */
    public static Date getNextDay(Date date, int i) {
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.set(Calendar.DATE, cal.get(Calendar.DATE) + i);
        return cal.getTime();
    }

    /**
     * 返回某个日期前几天的日期
     *
     * @param date
     * @param i
     * @return
     */
    public static Date getFrontDay(Date date, int i) {
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.set(Calendar.DATE, cal.get(Calendar.DATE) - i);
        return cal.getTime();
    }

    /**
     * 获取某年某月到某年某月按天的切片日期集合（间隔天数的日期集合）
     *
     * @param beginYear
     * @param beginMonth
     * @param endYear
     * @param endMonth
     * @param k
     * @return
     */
    public static List<List<Date>> getTimeList(int beginYear, int beginMonth, int endYear,
                                               int endMonth, int k) {
        List<List<Date>> list = new ArrayList<List<Date>>();
        if (beginYear == endYear) {
            for (int j = beginMonth; j <= endMonth; j++) {
                list.add(getTimeList(beginYear, j, k));

            }
        } else {
            {
                for (int j = beginMonth; j < 12; j++) {
                    list.add(getTimeList(beginYear, j, k));
                }

                for (int i = beginYear + 1; i < endYear; i++) {
                    for (int j = 0; j < 12; j++) {
                        list.add(getTimeList(i, j, k));
                    }
                }
                for (int j = 0; j <= endMonth; j++) {
                    list.add(getTimeList(endYear, j, k));
                }
            }
        }
        return list;
    }

    /**
     * 获取某年某月按天切片日期集合（某个月间隔多少天的日期集合）
     *
     * @param beginYear
     * @param beginMonth
     * @param k
     * @return
     */
    public static List<Date> getTimeList(int beginYear, int beginMonth, int k) {
        List<Date> list = new ArrayList<Date>();
        Calendar begincal = new GregorianCalendar(beginYear, beginMonth, 1);
        int max = begincal.getActualMaximum(Calendar.DATE);
        for (int i = 1; i < max; i = i + k) {
            list.add(begincal.getTime());
            begincal.add(Calendar.DATE, k);
        }
        begincal = new GregorianCalendar(beginYear, beginMonth, max);
        list.add(begincal.getTime());
        return list;
    }

    /**
     * 格式化日期
     * yyyy-MM-dd HH:mm:ss
     *
     * @param @param  date
     * @param @return
     * @Description:
     */
    private static Date format(Date date) {
        SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            date = sd.parse(sd.format(date));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }

    /**
     * Date转为Timestamp
     *
     * @param date
     * @return
     */
    public static Timestamp formatDate(Date date) {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = df.format(date);
        Timestamp ts = Timestamp.valueOf(time);
        return ts;
    }

    /**
     * 格式化date
     *
     * @param date
     * @return
     */
    public static String formatDateString(Date date) {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = df.format(date);
        return time;
    }

    /**
     * 格式化date
     *
     * @param date
     * @return
     */
    public static String formatDateMonthString(Date date) {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM");
        String time = df.format(date);
        return time;
    }

    /**
     * 格式化date
     *
     * @param timestamp 时间戳
     * @return 返回年月日时间
     */
    public static String formatTimestamp2DateString(Timestamp timestamp) {
        if (null == timestamp) {
            return "";
        }
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        return df.format(timestamp);
    }

    /**
     * 格式化date
     *
     * @param timestamp 时间戳
     * @return 返回年月日时间
     */
    public static String formatTimestamp2String(Timestamp timestamp, String formatForm) {
        if (null == timestamp) {
            return "";
        }
        SimpleDateFormat df = new SimpleDateFormat(formatForm);
        return df.format(timestamp);
    }

    /**
     * 格式化date
     *
     * @param timestamp 时间戳
     * @return 返回年月日时间
     */
    public static String formatTimestamp2DateStringPoint(Timestamp timestamp) {
        if (null == timestamp) {
            return "";
        }
        SimpleDateFormat df = new SimpleDateFormat("yyyy.MM.dd");
        return df.format(timestamp);
    }

    /**
     * 格式化date
     *
     * @param timestamp 时间戳
     * @return 返回年月日时间
     */
    public static String formatTimestamp2DateTimeString(Timestamp timestamp) {
        if (null == timestamp) {
            return "";
        }
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return df.format(timestamp);
    }

    /**
     * 获取距当天时间段的开始时间
     *
     * @return 默认格式 Wed May 31 14:47:18 CST 2017
     */
    public static Date getBeginDayOfDay(int day) {
        Calendar cal = new GregorianCalendar();
        cal.setTime(getDayBegin());
        cal.add(Calendar.DAY_OF_MONTH, day);
        return cal.getTime();
    }

    /**
     * 获取距当天时间段的结束时间
     *
     * @return 默认格式 Wed May 31 14:47:18 CST 2017
     */
    public static Date getEndDayOfDay(int day) {
        Calendar cal = new GregorianCalendar();
        cal.setTime(getDayEnd());
        cal.add(Calendar.DAY_OF_MONTH, day);
        return cal.getTime();
    }

    /**
     * 获取当前时间前3分钟
     *
     * @param
     * @return
     */
    public static Date getCurrentTime(Integer minute, Date date) {
        Calendar beforeTime = Calendar.getInstance();
        beforeTime.setTime(date);
        beforeTime.add(Calendar.MINUTE, minute);
        Date beforeD = beforeTime.getTime();
        return beforeD;
    }

    /**
     * 获取距某天天时间段的开始时间
     *
     * @return 默认格式 Wed May 31 14:47:18 CST 2017
     */
    public static Date getBeginDayOfDay(int day, Date date) {
        Calendar cal = new GregorianCalendar();
        cal.setTime(getDayStart(date));
        cal.add(Calendar.DAY_OF_MONTH, day);
        return cal.getTime();
    }

    /**
     * 获取距当天时间段的结束时间
     *
     * @return 默认格式 Wed May 31 14:47:18 CST 2017
     */
    public static Date getEndDayOfDay(int day, Date date) {
        Calendar cal = new GregorianCalendar();
        cal.setTime(getDayEnd(date));
        cal.add(Calendar.DAY_OF_MONTH, day);
        return cal.getTime();
    }

    /**
     * 获取某个日期的开始时间
     *
     * @param d
     * @return yyyy-MM-dd HH:mm:ss  格式
     */
    public static Date getDayStart(Date d) {

        Calendar calendar = Calendar.getInstance();
        if (null != d) calendar.setTime(d);
        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
        calendar.set(Calendar.MILLISECOND, 0);

        return calendar.getTime();
    }

    /**
     * 获取某个日期的结束时间
     *
     * @param d
     * @return yyyy-MM-dd HH:mm:ss  格式
     */
    public static Date getDayEnd(Date d) {

        Calendar calendar = Calendar.getInstance();
        if (null != d) calendar.setTime(d);
        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 23, 59, 59);
        calendar.set(Calendar.MILLISECOND, 999);

        return calendar.getTime();
    }

    /**
     * 获取过去num个月之前的时间戳
     *
     * @return yyyy-MM-dd HH:mm:ss  格式
     */
    public static Timestamp getPastNumMouth(int num) {

        LocalDateTime localDateTime = LocalDateTime.now();
        ZoneId zone = ZoneId.systemDefault();
        localDateTime = localDateTime.minusMonths(num);
        Instant instant = localDateTime.atZone(zone).toInstant();

        return Timestamp.from(instant);
    }

    /**
     * 获取过去num日之后的时间戳
     *
     * @return yyyy-MM-dd HH:mm:ss  格式
     */
    public static Timestamp getFutureTimestampAfterNumDays(int num) {

        LocalDateTime localDateTime = LocalDateTime.now();
        ZoneId zone = ZoneId.systemDefault();
        localDateTime = localDateTime.plusDays(num);
        Instant instant = localDateTime.atZone(zone).toInstant();

        return Timestamp.from(instant);
    }

    /**
     * 获取过去num日之后的时间戳
     *
     * @return yyyy-MM-dd HH:mm:ss  格式
     */
    public static Timestamp getFutureTimestampAfterNumMouths(int num) {

        LocalDateTime localDateTime = LocalDateTime.now();
        ZoneId zone = ZoneId.systemDefault();
        localDateTime = localDateTime.plusMonths(num);
        Instant instant = localDateTime.atZone(zone).toInstant();

        return Timestamp.from(instant);
    }

    /**
     * 获取过去几个月之前的日期
     *
     * @return yyyy-MM-dd HH:mm:ss.f  格式
     */
    public static Timestamp nowTimestamp() {

        LocalDateTime localDateTime = LocalDateTime.now();
        ZoneId zone = ZoneId.systemDefault();
        Instant instant = localDateTime.atZone(zone).toInstant();

        return Timestamp.from(instant);
    }

    /**
     * 时间字符串转timestamp
     *
     * @param dateStr 时间字符串
     * @param pattern 时间格式
     * @return {@link Timestamp}
     */
    public static Timestamp string2Timestamp(String dateStr, String pattern) {

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        LocalDateTime localDateTime = LocalDateTime.from(formatter.parse(dateStr));

        return Timestamp.valueOf(localDateTime);
    }

    /**
     * 时间字符串转timestamp
     *
     * @param timestamp 时间戳
     * @return {@link Timestamp}
     */
    public static String timestamp2String(Timestamp timestamp, String pattern) {

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        LocalDateTime dateTime = Instant.ofEpochMilli(timestamp.getTime()).atZone(ZoneId.systemDefault()).toLocalDateTime();

        return dateTime.format(formatter);
    }

    /**
     * 时间字符串转timestamp, 默认时间格式 yyyy-m [m] -d [d] hh：mm：ss [.f ...]
     *
     * @param dateStr 时间字符串
     * @return {@link Timestamp}
     */
    public static Timestamp string2Timestamp(String dateStr) {
        return Timestamp.valueOf(dateStr);
    }

    /**
     * 时间字符串转timestamp, 字符串时间格式 yyyy-MM-dd
     *
     * @param dateStr 时间字符串
     * @return {@link Timestamp}
     */
    public static Timestamp yyyyMMddString2Timestamp(String dateStr, boolean startDay) {

        LocalDate date = LocalDate.parse(dateStr);
        if (startDay) {
            return Timestamp.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant());
        }
        LocalDateTime ldt = date.atTime(LocalTime.MAX);

        return Timestamp.valueOf(ldt);
    }

    /**
     * 获取一天的第一个时间戳, 字符串时间格式 yyyy-MM-dd
     *
     * @param dateStr 时间字符串
     * @return {@link Timestamp} 一天最开始的时间戳
     */
    public static Timestamp startOfDay(String dateStr) {
        return yyyyMMddString2Timestamp(dateStr, true);
    }

    /**
     * 获取一天的最后一个时间戳, 字符串时间格式 yyyy-MM-dd
     *
     * @param dateStr 时间字符串
     * @return {@link Timestamp} 一天最后的时间戳
     */
    public static Timestamp endOfDay(String dateStr) {
        return yyyyMMddString2Timestamp(dateStr, false);
    }

    /**
     * 时间字符串转timestamp, 输入字符串时间格式 yyyy-MM-dd
     *
     * @param dateStr 时间字符串
     * @return {@link Timestamp} 一个月第一天
     */
    public static Timestamp startOfMonth(String dateStr) {

        LocalDate date = LocalDate.parse(dateStr);
        date = date.with(TemporalAdjusters.firstDayOfMonth());

        return Timestamp.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 本月第一个时间戳
     *
     * @return {@link Timestamp} 一个月第一天
     */
    public static Timestamp startOfCurrentMonth() {

        LocalDate date = LocalDate.now();
        date = date.with(TemporalAdjusters.firstDayOfMonth());

        return Timestamp.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 本月最后一个时间戳
     *
     * @return {@link Timestamp} 本月最后一个时间戳
     */
    public static Timestamp endOfCurrentMonth() {

        LocalDate date = LocalDate.now();
        date = date.with(TemporalAdjusters.lastDayOfMonth());
        Timestamp endTime = Timestamp.valueOf(date.atTime(LocalTime.MAX));
        /*
         * 目的是：防止mysql精度进位，但是也同时带来风险
         *  例如：2020-10-01 23:59:59.999999，如果没有setNanos(0),将导致mysql进位，存储为 2020-10-02 00:00:00
         */
        return DateUtils.setTimestampNanosTo0(endTime);
    }

    /**
     * 时间字符串转timestamp, 输入字符串时间格式 yyyy-MM-dd
     *
     * @param dateStr 时间字符串
     * @return {@link Timestamp} 时间戳
     */
    public static Timestamp endOfMonth(String dateStr) {

        LocalDate date = LocalDate.parse(dateStr);
        date = date.with(TemporalAdjusters.lastDayOfMonth());
        LocalDateTime ldt = date.atTime(LocalTime.MAX);

        return Timestamp.valueOf(ldt);
    }

    /**
     * 计算两个时间差几天
     *
     * @param t1 时间1
     * @param t2 时间2
     * @return {@link Timestamp} 时间差
     */
    public static long subOfDays(Timestamp t1, Timestamp t2) {

        LocalDate ld1 = Instant.ofEpochMilli(t1.getTime()).atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate ld2 = Instant.ofEpochMilli(t2.getTime()).atZone(ZoneId.systemDefault()).toLocalDate();

        return Math.abs(ChronoUnit.DAYS.between(ld1, ld2));
    }

    /**
     * @param startTime yyyy-MM
     * @param endTime   yyyy-MM
     * @return 返回月份差 例如:2020-01   2020-05   返回2020-03
     */
    public static int getTwoDateDifference(String startTime, String endTime) {

        String date = "-01";
        startTime = startTime + date;
        endTime = endTime + date;
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate localStartDate = LocalDate.parse(startTime, formatter);
        LocalDate localEndDate = LocalDate.parse(endTime, formatter);
        Period period = Period.between(localStartDate, localEndDate);

        return period.getYears() * 12 + period.getMonths() + 1;
    }

    /**
     * @param date yyyy-MM
     * @param num  获取前几个月时间
     * @return date:2020-08  int:5  2020-
     */
    public static String getBeforeYearMonthTime(String date, int num) {

        String dateTime = "-01";
        date = date + dateTime;
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate localStartDate = LocalDate.parse(date, formatter);
        LocalDate localDate = localStartDate.minusMonths(num);

        return localDate.format(DateTimeFormatter.ofPattern("yyyy-MM"));
    }

    /**
     * 获取某一个月的结束时间
     *
     * @param time 格式yyyy-MM
     * @return yyyy-MM-dd HH:mm:ss
     */
    public static String getMonthEndTimeStr(String time) {

        time = time + "-01 23:59:59";
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(FORMAT_YYYYMMDD_HHMMSS);
        LocalDateTime localStartDate = LocalDateTime.parse(time, formatter);
        LocalDateTime with = localStartDate.with(TemporalAdjusters.lastDayOfMonth());

        return formatter.format(with);
    }

    /*
     * 目的是：防止mysql精度进位，但是也同时带来风险
     *  例如：2020-10-01 23:59:59.999999，如果没有setNanos(0),将导致mysql进位，存储为 2020-10-02 00:00:00
     */
    public static Timestamp setTimestampNanosTo0(Timestamp time) {
        time.setNanos(0);
        return time;
    }

    public static boolean isSameMonth(Timestamp t1, Timestamp t2) {
        LocalDateTime localT1 = t1.toLocalDateTime();
        LocalDateTime localT2 = t2.toLocalDateTime();
        return localT1.getYear() == localT2.getYear() && localT1.getMonth() == localT2.getMonth();
    }
}
